/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.muni.fi.pa165.bookingmanager.web;

import cz.muni.fi.pa165.bookingmanager.adapters.CustomerAdapter;
import cz.muni.fi.pa165.bookingmanager.adapters.ReservationAdapter;
import cz.muni.fi.pa165.bookingmanager.adapters.RoomAdapter;
import cz.muni.fi.pa165.bookingmanager.dto.CustomerDTO;
import cz.muni.fi.pa165.bookingmanager.dto.HotelDTO;
import cz.muni.fi.pa165.bookingmanager.dto.ReservationDTO;
import cz.muni.fi.pa165.bookingmanager.exceptions.IllegalOrphanException;
import cz.muni.fi.pa165.bookingmanager.exceptions.NonexistentEntityException;
import cz.muni.fi.pa165.bookingmanager.exceptions.PreexistingEntityException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import net.sourceforge.stripes.action.*;
import net.sourceforge.stripes.controller.LifecycleStage;
import net.sourceforge.stripes.validation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Štefan Repček
 */
@UrlBinding("/admin/reservation/${event}")
public class ReservationActionBean extends MyActionBean {

    final static Logger log = LoggerFactory.getLogger(ReservationActionBean.class);
    private List<ReservationDTO> list = new ArrayList<ReservationDTO>();
    private List<Long> customerList = new ArrayList<Long>();
    private Date dateFrom;
    private Date dateTo;
    private ReservationAdapter reservationAdapter;
    private CustomerAdapter customerAdapter;
    @Validate(on = {"add"}, required = true)
    private Long roomID;
    private RoomAdapter roomAdapter;
    private Date date;
    private String searchedRoomNumber;
    @ValidateNestedProperties(value = {
        @Validate(on = {"add", "save"}, field = "duration", required = true, minvalue = 1)
    })
    private ReservationDTO reservation;

    public String getsearchedRoomNumber() {
        return searchedRoomNumber;
    }

    public void setsearchedRoomNumber(String searchedRoomNumber) {
        this.searchedRoomNumber = searchedRoomNumber;
    }

    public Long getRoomID() {
        return roomID;
    }

    public void setRoomID(Long roomID) {
        this.roomID = roomID;
    }

    public Date getDate() {
        if (date == null) {
            return null;
        }

        return new Date(date.getTime());
    }

    public Date getDateFrom() {
        if (dateFrom == null) {
            return null;
        }

        return new Date(dateFrom.getTime());
    }

    public Date getDateTo() {
        if (dateTo == null) {
            return null;
        }

        return new Date(dateTo.getTime());
    }

    public List<Long> getCustomerList() {
        return Collections.unmodifiableList(customerList);
    }

    public void setCustomerList(List<Long> customerList) {
        this.customerList = new ArrayList<Long>();
        this.customerList.addAll(customerList);
    }

    @Validate(on = {"add", "save"}, mask = "\\d{2}/\\d{2}/\\d{4}", required = true, converter = DateTypeConverter.class)
    public void setDate(Date date) {
        this.date = new Date(date.getTime());
    }

    @Validate(converter = DateTypeConverter.class)
    public void setDateFrom(Date dateFrom) {
        this.dateFrom = new Date(dateFrom.getTime());
    }

    @Validate(converter = DateTypeConverter.class)
    public void setDateTo(Date dateTo) {
        this.dateTo = new Date(dateTo.getTime());
    }

    public ReservationActionBean() throws NamingException {
        Context ctx = new InitialContext();
        this.reservationAdapter = (ReservationAdapter) ctx.lookup("java:global/cz.muni.fi.pa165.bookingmanager_booking_manager-web_war_1.0-SNAPSHOT/ReservationAdapterImpl!cz.muni.fi.pa165.bookingmanager.adapters.ReservationAdapter");
        this.customerAdapter = (CustomerAdapter) ctx.lookup("java:global/cz.muni.fi.pa165.bookingmanager_booking_manager-web_war_1.0-SNAPSHOT/CustomerAdapterImpl!cz.muni.fi.pa165.bookingmanager.adapters.CustomerAdapter");
        this.roomAdapter = (RoomAdapter) ctx.lookup("java:global/cz.muni.fi.pa165.bookingmanager_booking_manager-web_war_1.0-SNAPSHOT/RoomAdapterImpl!cz.muni.fi.pa165.bookingmanager.adapters.RoomAdapter");
    }

    @Before(stages = LifecycleStage.CustomValidation, on = {"add"})
    public void beforeAddValidate() {
        list = reservationAdapter.findAllHotelReservations(getContext().getHotel());
    }

    @DefaultHandler
    public Resolution all() {
        log.debug("all()");
        list = reservationAdapter.findAllHotelReservations(getContext().getHotel());
        return new ForwardResolution("/backend/hotels/reservations/list.jsp");
    }

    public Resolution add() throws PreexistingEntityException, IllegalOrphanException {
        log.debug("add() reservation={}", reservation);
        List<CustomerDTO> customers = new ArrayList<CustomerDTO>();
        for (Long id : customerList) {
            customers.add(customerAdapter.getCustomerById(id));
        }
        reservation.setCustomers(customers);
        if (customers.isEmpty()) {
            ValidationErrors errors = getContext().getValidationErrors();
            errors.addGlobalError(new LocalizableError("frontend.emptyCustomers"));
            getContext().setValidationErrors(errors);
            return getContext().getSourcePageResolution();
        }
        reservation.setHotel(getContext().getHotel());
        reservation.setStartDate(new java.sql.Date(date.getTime()));
        reservation.setRoom(roomAdapter.getRoomById(roomID));
        reservation.setTotalPrice(reservation.getRoom().getPrice().multiply(BigDecimal.valueOf(reservation.getDuration())));
        reservationAdapter.createReservation(reservation);
        return new RedirectResolution(this.getClass(), "all");
    }

    public ReservationDTO getReservation() {
        return reservation;
    }

    public void setReservation(ReservationDTO Reservation) {
        this.reservation = Reservation;
    }

    @Before(stages = LifecycleStage.BindingAndValidation, on = {"delete", "edit", "save"})
    public void loadReservationFromDatabase() {
        String ids = getContext().getRequest().getParameter("reservation.id");
        if (ids == null) {
            return;
        }
        reservation = reservationAdapter.getResevationById(Long.parseLong(ids));
    }

    public Resolution edit() {
        log.debug("edit() reservation={}", reservation);
        return new ForwardResolution("/backend/hotels/reservations/edit.jsp");
    }

    public Resolution save() throws NonexistentEntityException, IllegalOrphanException, PreexistingEntityException, Exception {
        log.debug("save() reservation={}", reservation);
        reservation.setStartDate(new java.sql.Date(date.getTime()));
        reservation.setTotalPrice(reservation.getRoom().getPrice().multiply(BigDecimal.valueOf(reservation.getDuration())));
        reservationAdapter.updateReservation(reservation);
        return new RedirectResolution(this.getClass(), "all");
    }

    public Resolution delete() throws NonexistentEntityException, IllegalOrphanException {
        log.debug("delete({})", reservation.getId());
        reservationAdapter.deleteReservation(reservation);
        return new RedirectResolution(this.getClass(), "all");
    }

    public List<ReservationDTO> getList() {
        if (this.list == null) {
            return null;
        }
        return Collections.unmodifiableList(list);
    }

    public void setList(List<ReservationDTO> list) {
        this.list = new ArrayList<ReservationDTO>();
        this.list.addAll(list);
    }

    public Resolution findHotelReservationsFromTo() {
        List<ReservationDTO> helpList;
        if (dateFrom == null && dateTo == null && searchedRoomNumber == null) {
            return new RedirectResolution(this.getClass(), "all");

        } else if (dateFrom != null && dateTo == null && searchedRoomNumber == null) {
            list = reservationAdapter.findAllHotelReservations(getContext().getHotel(), new java.sql.Date(dateFrom.getTime()));

        } else if (dateFrom == null && dateTo != null && searchedRoomNumber == null) {
            helpList = reservationAdapter.findAllHotelReservations(getContext().getHotel());
            for (ReservationDTO res : helpList) {
                if (res.getStartDate().compareTo(new java.sql.Date(dateTo.getTime())) <= 0) {
                    list.add(res);
                }
            }
        } else if (dateFrom == null && dateTo == null && searchedRoomNumber != null) {
            list = reservationAdapter.findAllRoomReservations(roomAdapter.findRoomByNumber(searchedRoomNumber, getContext().getHotel()));

        } else if (dateFrom != null && dateTo != null && searchedRoomNumber == null) {
            helpList = reservationAdapter.findAllHotelReservations(getContext().getHotel(), new java.sql.Date(dateFrom.getTime()));

            for (ReservationDTO res : helpList) {
                if (res.getStartDate().compareTo((new java.sql.Date(dateTo.getTime()))) <= 0) {
                    list.add(res);
                }
            }
        } else if (dateFrom != null && dateTo == null && searchedRoomNumber != null) {
            list = reservationAdapter.findAllRoomReservations(roomAdapter.findRoomByNumber(searchedRoomNumber, getContext().getHotel()));

        } else if (dateFrom == null && dateTo != null && searchedRoomNumber != null) {
            helpList = reservationAdapter.findAllRoomReservations(roomAdapter.findRoomByNumber(searchedRoomNumber, getContext().getHotel()));

            for (ReservationDTO res : helpList) {
                if (res.getStartDate().compareTo((new java.sql.Date(dateTo.getTime()))) <= 0) {
                    list.add(res);
                }
            }
        } else {
            helpList = reservationAdapter.findAllRoomReservations(roomAdapter.findRoomByNumber(searchedRoomNumber, getContext().getHotel()));
            if (helpList != null) {
                for (ReservationDTO res : helpList) {
                    if (res.getStartDate().compareTo((new java.sql.Date(dateTo.getTime()))) <= 0) {
                        list.add(res);
                    }
                }
            }
        }
        return new ForwardResolution("/backend/hotels/reservations/list.jsp");
    }
}
